{Todo: Realizar rutina de carga}
{ Copyright (C) 2010 Jorge Turiel <contact>

  This source is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free
  Software Foundation; either version 2 of the License, or (at your option)
  any later version.

  This code is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  details.

  A copy of the GNU General Public License is available on the World Wide Web
  at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
  to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  MA 02111-1307, USA.}

Unit uBoards;

{$mode objfpc}{$H+}

Interface

Uses
Classes, SysUtils,XMLWrite,XMLRead,DOM;

Type TUpload = Record
  Protocol     : String;
  maximum_size : Integer;
  Speed        : Integer;
End;

Type TBootloader = Record
  low_fuses      : String;
  high_fuses     : String;
  extended_fuses : string;
  path           : string;
  files          : string;
  unlock_bits    : String;
  lock_bits      : String;
End;

Type  TBuild = Record
  mcu    : String;
  f_cpu  : String;
  core   : String;
End;

Type

 { TArduino }

  TArduino = Class
    name        : String;
    Descripcion : String;
    Upload      : TUpload;
    BootLoader  : TBootLoader;
    Build       : TBuild;
    Constructor Create;
  End;

Type

{ TPlacas }

  TPlacas = Class
    Private
    //RutaDatos : String;
    Procedure AddElementos (Var Registro : TArduino;Elementos: Array Of String );
    Procedure Procesar (Lineas : TStringList);
    Procedure Elementos (Cadena : String; Var Elementos: Array Of String);
    Procedure CargarTxt (Boards : String);
    Procedure SaveBoards (Ruta : String);
    Public
    Placas : Array Of TArduino;
    Constructor Create;
    Destructor Destroy;override;
    Function Contar: Integer;
    Function ADD (Placa : TArduino): Boolean;
    Procedure Importar (stOrigen,stDestino:String);
    Procedure CargarXML (stOrigen : string);
  End;
Function IsHex(s: String): boolean;

Implementation
uses unit1;
Function IsHex(s: String): boolean;

Var
  i: integer;
Begin
  Result := True;
  For i := 1 To length(s) Do
    If Not (char(s[i]) In ['0'..'9']) And Not (char(s[i]) In ['A'..'F']) Then
      Begin
        Result := False;
        exit;
      End;
End;
{ TArduino }


constructor TArduino.Create;
Begin

End;

{ TPlacas }
Procedure TPlacas.Importar (stOrigen,stDestino:String);
Begin
  CargarTxt (stOrigen);
  SaveBoards (stDestino);
end;

procedure TPlacas.CargarXML (stOrigen: string );
Var
  I : Integer;
  xdoc: TXMLDocument;
  NodoPadre: TDOMNode;
  NodoHijo: TDOMNode;
  Registro: TArduino;
begin
 Try
   ReadXMLFile(xdoc,stOrigen);
   SetLength (Placas,0);

   For I:= 0 TO xDoc.DocumentElement.ChildNodes.Count-1 do
   Begin
      Registro := TArduino.create;
      NodoPadre := xDoc.DocumentElement.ChildNodes[i];
      //Nombre
      Registro.name:=NodoPadre.Attributes.Item[0].TextContent;

      //Descripcion
      Registro.Descripcion:=NodoPadre.ChildNodes[0].TextContent;

      //Upload
      NodoHijo := NodoPadre.ChildNodes[1];

      //Upload.Protocol
      Registro.Upload.Protocol:=NodoHijo.ChildNodes[0].TextContent;

      //Upload.MaximunSize
      Registro.Upload.maximum_size:=StrToInt(NodoHijo.ChildNodes[1].TextContent);

      //Upload.speed;
      Registro.Upload.Speed:=StrToInt (NodoHijo.ChildNodes[2].TextContent);

      // BootLoader
      NodoHijo := NodoPadre.ChildNodes[2];

      //BootLoader.Low_fuses
      Registro.BootLoader.low_fuses:=NodoHijo.ChildNodes[0].TextContent;

      //BootLoader.High_fuses
      Registro.BootLoader.high_fuses:=NodoHijo.ChildNodes[1].TextContent;

      //BootLoader.extended_fuses
      Registro.BootLoader.extended_fuses:=NodoHijo.ChildNodes[2].TextContent;

      //BootLoader.path
      Registro.BootLoader.path:=NodoHijo.ChildNodes[3].TextContent;

      //BootLoader.file
      Registro.BootLoader.files:=NodoHijo.ChildNodes[4].TextContent;

      //BootLoader.unlock_bits
      Registro.BootLoader.unlock_bits:=NodoHijo.ChildNodes[5].TextContent;

      //BootLoader.lock_bits
      Registro.BootLoader.lock_bits:=NodoHijo.ChildNodes[6].TextContent;

      //Build
      NodoHijo := NodoPadre.ChildNodes[3];

      //Build.mcu
      Registro.Build.mcu:=NodoHijo.ChildNodes[0].TextContent;

      //Build.f_cpu
      Registro.Build.f_cpu:=NodoHijo.ChildNodes[1].TextContent;

      //Build.core
      Registro.Build.core:=NodoHijo.ChildNodes[2].TextContent;
      Add (Registro);
      Registro := nil;
   end;
 finally
   If REgistro <> Nil Then
     Registro := Nil;
 end;


end;

Procedure TPlacas.Procesar (Lineas: TStringList );

Var
  I: Integer;
  Cadena: string;
  lsTemp : TStringList;
  Partes : Array Of String;
  Bloque : Boolean;
 //c0,c1,c2,c3 : string;
  j: Integer;
  Registro: TArduino;

Begin
  lsTemp := TStringList.Create;
  lsTemp.Clear;
  Bloque := False;
  //Form1.Memo1.Lines.Assign (Lineas);
  i:=0;
  While I < Lineas.Count-1 do
  Begin
    Cadena := Lineas[i];
    IF Length (Cadena) > 0 Then
    Begin
      If (Cadena[1]>#64)  Then
      Begin
        //Inc (i);
        Bloque := False;
        lsTemp.Clear;
        While (Bloque = False) and (I < Lineas.Count-1) do
        Begin
             Cadena := Lineas[I];

             If Length (Cadena) > 0 Then
             Begin
               If Cadena[1] > #64 Then
               Begin
                 lsTEmp.Add(Cadena);
               end
               Else
               Begin
                    Bloque := True
               end;
             end;
             Inc (I);
        end;
        Registro := TArduino.Create;
        For j:=0 To LsTemp.Count-1 do
        Begin
            SetLength (Partes,4);

            Elementos (lsTemp[j],Partes);
            //c0 := Partes[0];
            //c1 := Partes[1];
            //c2 := Partes[2];
            //c3 := Partes[3];

            AddElementos (REgistro,Partes);

        end;
        ADD (Registro);
        Registro := nil;
        SetLength (Partes,0);
      end;

  end;
   Inc (I);
End;

end;

Procedure TPlacas.AddElementos (Var Registro : Tarduino;Elementos: Array Of String);
Begin
  //Si está vacio salir
  If Length (Elementos) < 1 Then Exit;
 // Registro := TArduino.Create;
  //Sino lo encontró, añadir dato al registro actual
    Begin
      IF Elementos[1] = 'name' Then
      Begin
        Registro.name:= Elementos[0];
        Registro.Descripcion:=Elementos[2];
      end;
      If Elementos[1] = 'upload' Then
        Begin
          If Elementos[2] = 'protocol' Then
            Begin
              Registro.Upload.Protocol := Elementos[3];
            End;
          If Elementos[2] = 'maximum_size' Then
            Begin
              Registro.Upload.maximum_size := StrToInt(Elementos[3]);
            End;
          If Elementos[2] = 'speed' Then
            Begin
              Registro.Upload.Speed := StrToInt(Elementos[3]);
            End;
        End;
      If Elementos[1] = 'bootloader' Then
        Begin
          If Elementos[2] = 'low_fuses' Then
          Begin
            Registro.BootLoader.low_fuses := Elementos[3];
          end;
          If Elementos[2] = 'high_fuses' Then
          Begin
               Registro.BootLoader.high_fuses := Elementos[3];
          End;
          If Elementos[2] = 'extended_fuses' Then
          Begin
               Registro.BootLoader.extended_fuses := Elementos[3];
          End;
          If Elementos[2] = 'path' Then
          Begin
               Registro.BootLoader.path := Elementos[3];
          End;
          If Elementos[2] = 'file' Then
          Begin
               Registro.BootLoader.files := Elementos[3];
          End;
          If Elementos[2] = 'unlock_bits' Then
          Begin
               Registro.BootLoader.unlock_bits := Elementos[3];
          End;
          If Elementos[2] = 'lock_bits' Then
          Begin
               Registro.BootLoader.lock_bits := Elementos[3];
          End;
        End;
        End;
      If Elementos[1] = 'build' Then
        Begin
         IF Elementos[2]='mcu' Then
         Begin
          Registro.Build.mcu:=Elementos[3];
         end;
         If ELementos[2] = 'f_cpu' Then
         Begin
          Registro.Build.f_cpu:=Elementos[3];
         end;
         If Elementos[2] = 'core' Then
         Begin
          Registro.Build.core:=Elementos[3];
         end;
        End;

End;



Procedure TPlacas.Elementos (Cadena: String; Var Elementos: Array Of String );

Var
  Posicion: LongInt;
  RestoCadena : String;
  indice : integer;
  PosIgual: Integer;
Begin
  indice := 0;
  //Cadena de ejemplo: atmega328.upload.protocol=stk500
  //Encuentra primer punto
  Posicion := Pos ('.',Cadena);

  //Copia hasta el primer punto
  Elementos[indice] := Copy(Cadena,1,Posicion-1);
  Inc (indice);
  //RestoCadena, contiene desde el primer punto,
  //ej: upload.protocol=stk500
  RestoCadena := Copy (Cadena,Posicion+1,Length(Cadena));

  //Busca un nuevo punto
  Posicion := Pos ('.',RestoCadena);
  PosIgual := Pos ('=',RestoCadena);
  If (Posicion > 0) and (Posicion < PosIgual) Then
  Begin
  //Copia lo que hay antes del punto, ej: upload
  Elementos[indice] := Copy (RestoCadena,0,Posicion-1);

  //Se queda con lo que hay después del punto: protocol=stk500 )
  RestoCadena := Copy (RestoCadena,Posicion+1,Length(RestoCadena));
  Inc (indice);

  end;
  //Busca la posición del igual
  Posicion := Pos ('=',RestoCadena);
 If Posicion > 0 Then
 Begin
  //Guarda lo que hay antes del igual
  Elementos[indice] := Copy (RestoCadena,0,Posicion-1);
  Inc (Indice);
  //Guarda lo que hay después del igual
  Elementos[indice] := Copy (RestoCadena,Posicion+1,Length(RestoCadena));

 end;
End;


constructor TPlacas.Create;
Begin
// RutaDatos:=MiDirectorio+PathDelim+'Datos'+PathDelim;
End;

procedure TPlacas.CargarTxt (Boards: String );
Var
  Texto : TStringList;
Begin
  SetLength (Placas,0);
  If Not FileExists (Boards) Then Exit;
  Texto := TStringList.Create;
  Try
    Texto.LoadFromFile(Boards);
    Procesar (Texto);
  Finally
    Texto.Free;
  End;

end;

destructor TPlacas.Destroy;

Begin
  SetLength(Placas,0);
  inherited Destroy;
End;

Function TPlacas.Contar: Integer;
Begin

  Result := Length(Placas);
End;
//No pueden existe dos placas iguales
Function TPlacas.ADD (Placa: TArduino ): Boolean;

Var
  Dimension : Integer;
  //I: Integer;
  //Registro : Tarduino;
  //existe: Boolean;
Begin
  Result := False;
  //Registro := TArduino.Create;
  //Existe := False;
  //i := 0;
  //While I < Length (Placas)-1 Do
  //  Begin
  //    Registro := Nil;
  //    Registro := Placas[i];
  //    If Registro.name = Placa.name Then
  //      Begin
  //        existe := True;
  //        i := length (Placas);
  //      End;
  //  End;
  //If Not Existe Then
  //  Begin
  //    Dimension := Length (Placas);
  //    SetLength (Placas,Dimension+1);
  //    Placas[Dimension] := Placa;
  //    Result := True;
  //  End;
       Dimension := Length (Placas);
      SetLength (Placas,Dimension+1);
      Placas[Dimension] := Placa;
      Result := True;
End;



procedure TPlacas.SaveBoards (Ruta: String );
Var
  xDoc : TXMLDocument;
  RootNode: TDOMElement;
  I: Integer;
  Registro: TArduino;
  ParentNode: TDOMElement;
  NodoHijo: TDOMText;
  NodoHijo1: TDOMElement;
  NodoHijo2: TDOMText;
begin
  IF Length (Placas) <1 Then Exit;
  //Crear documento XML
  xDoc := TXMLDocument.create;
  //Crear nodo Raiz
  RootNode := xDoc.CreateElement('Placas');
  xDoc.AppendChild(RootNode);
  Registro := TArduino.Create;
  For I := 0 To Length (Placas)-1 do
  Begin
      Registro := Placas[I];
     //Nodo Padre
     RootNode:= XDoc.DocumentElement;
     ParentNode :=xDoc.CreateElement('Placa');
     TDOMElement(ParentNode).SetAttribute('Nombre',Registro.name);
     //Nombre
     RootNode.AppendChild(ParentNode);
     ParentNode := xDoc.CreateElement('Descripcion');
     NodoHijo := xDoc.CreateTextNode(Registro.Descripcion);
     ParentNode.AppendChild(NodoHijo);
     RootNode.ChildNodes.Item[I].AppendChild(ParentNode);
     ParentNode := xDoc.CreateElement('Upload');
     NodoHijo1 := Xdoc.CreateElement('protocol');
     NodoHijo2 := xDoc.CreateTextNode(Registro.Upload.Protocol);
     NodoHijo1.AppendChild(NodoHijo2);
     ParentNode.AppendChild(NodoHijo1);

     NodoHijo1 := xDoc.CreateElement('maximum_size');
     NodoHijo2 := xDoc.CreateTextNode(IntToStr (Registro.Upload.maximum_size));
     NodoHijo1.AppendChild(NodoHijo2);
     ParentNode.AppendChild(NodoHijo1);

     NodoHijo1 := xDoc.CreateElement('speed');
     NodoHijo2 := xDoc.CreateTextNode(IntToStr (Registro.Upload.Speed));
     NodoHijo1.AppendChild(NodoHijo2);
     ParentNode.AppendChild(NodoHijo1);
     //</Upload>
     RootNode.ChildNodes.Item[I].AppendChild(ParentNode);
     //BootLoader <bootloader>
     ParentNode := xDoc.CreateElement('bootloader');
     //<Low_fuses>
     NodoHijo1 := xDoc.CreateElement('low_fuses');
     NodoHijo2 := xDoc.CreateTextNode(Registro.BootLoader.low_fuses);
     NodoHijo1.AppendChild(NodoHijo2);
     ParentNode.AppendChild(NodoHijo1);

     //high_fuses
     NodoHijo1 := xDoc.CreateElement('high_fuses');
     NodoHijo2 := xDoc.CreateTextNode(Registro.BootLoader.high_fuses);
     NodoHijo1.AppendChild(NodoHijo2);
     ParentNode.AppendChild(NodoHijo1);

     // extended_fuses

     NodoHijo1 := xDoc.CreateElement('extended_fuses');
     NodoHijo2 := xDoc.CreateTextNode(Registro.BootLoader.extended_fuses);
     NodoHijo1.AppendChild(NodoHijo2);
     ParentNode.AppendChild(NodoHijo1);

     //path
     NodoHijo1 := xDoc.CreateElement('path');
     NodoHijo2 := xDoc.CreateTextNode(Registro.BootLoader.path);
     NodoHijo1.AppendChild(NodoHijo2);
     ParentNode.AppendChild(NodoHijo1);

     //file
     NodoHijo1 := xDoc.CreateElement('file');
     NodoHijo2 := xDoc.CreateTextNode(Registro.BootLoader.files);
     NodoHijo1.AppendChild(NodoHijo2);
     ParentNode.AppendChild(NodoHijo1);

     //unlock_bits
     NodoHijo1 := xDoc.CreateElement('unlock_bits');
     NodoHijo2 := xDoc.CreateTextNode(Registro.BootLoader.unlock_bits);
     NodoHijo1.AppendChild(NodoHijo2);
     ParentNode.AppendChild(NodoHijo1);

     //lock_bits
     NodoHijo1 := xDoc.CreateElement('lock_bits');
     NodoHijo2 := xDoc.CreateTextNode(REgistro.BootLoader.lock_bits);
     NodoHijo1.AppendChild(NodoHijo2);
     ParentNode.AppendChild(NodoHijo1);
     RootNode.ChildNodes.Item[I].AppendChild(ParentNode);  //</BootLoader>

     //<Build>

     ParentNode := xDoc.CreateElement('build');
     //mcu
      NodoHijo1 := xDoc.CreateElement('mcu');
      NodoHijo2 := xDoc.CreateTextNode(Registro.Build.mcu);
      NodoHijo1.AppendChild(NodoHijo2);
      ParentNode.AppendChild(NodoHijo1);

      //f_cpu
      NodoHijo1 := xDoc.CreateElement('f_cpu');
      NodoHijo2 := xDoc.CreateTextNode(Registro.Build.f_cpu);
      NodoHijo1.AppendChild(NodoHijo2);
      ParentNode.AppendChild(NodoHijo1);

      //core
      NodoHijo1 := xDoc.CreateElement('core');
      NodoHijo2 := xDoc.CreateTextNode(Registro.Build.core);
      NodoHijo1.AppendChild(NodoHijo2);
      ParentNode.AppendChild(NodoHijo1);

      RootNode.ChildNodes.Item[I].AppendChild(ParentNode); //</Build>

  end;




   //Guardar Fichero XML
   IF Not DirectoryExists  (ExtractFilePath(Ruta)) Then
   Begin
    CreateDir (ExtractFilePath(Ruta));
   end;
   WriteXMLFile (xdoc,Ruta);
   xdoc.free;
end;
End.

